-
Notifications
You must be signed in to change notification settings - Fork 345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
✨ Permit2 ERC20 #1093
✨ Permit2 ERC20 #1093
Conversation
let from_ := shl(96, from) | ||
if iszero(eq(caller(), _PERMIT2)) { | ||
// Compute the allowance slot and load its value. | ||
mstore(0x20, caller()) | ||
mstore(0x0c, or(from_, _ALLOWANCE_SLOT_SEED)) | ||
let allowanceSlot := keccak256(0x0c, 0x34) | ||
let allowance_ := sload(allowanceSlot) | ||
// If the allowance is not the maximum uint256 value. | ||
if not(allowance_) { | ||
// Revert if the amount to be transferred exceeds the allowance. | ||
if gt(amount, allowance_) { | ||
mstore(0x00, 0x13be252b) // `InsufficientAllowance()`. | ||
revert(0x1c, 0x04) | ||
} | ||
// Subtract and store the updated allowance. | ||
sstore(allowanceSlot, sub(allowance_, amount)) | ||
} | ||
} | ||
// Compute the balance slot and load its value. | ||
mstore(0x0c, or(from_, _BALANCE_SLOT_SEED)) | ||
let fromBalanceSlot := keccak256(0x0c, 0x20) | ||
let fromBalance := sload(fromBalanceSlot) | ||
// Revert if insufficient balance. | ||
if gt(amount, fromBalance) { | ||
mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`. | ||
revert(0x1c, 0x04) | ||
} | ||
// Subtract and store the updated allowance. | ||
sstore(allowanceSlot, sub(allowance_, amount)) | ||
// Subtract and store the updated balance. | ||
sstore(fromBalanceSlot, sub(fromBalance, amount)) | ||
// Compute the balance slot of `to`. | ||
mstore(0x00, to) | ||
let toBalanceSlot := keccak256(0x0c, 0x20) | ||
// Add and store the updated balance of `to`. | ||
// Will not overflow because the sum of all user balances | ||
// cannot exceed the maximum uint256 value. | ||
sstore(toBalanceSlot, add(sload(toBalanceSlot), amount)) | ||
// Emit the {Transfer} event. | ||
mstore(0x20, amount) | ||
log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This chunk of code is the same for both branches, with the only exception being that for the _givePermit2InfiniteAllowance()
branch, if msg.sender == _PERMIT2
, the allowance logic will be skipped.
// If `spender == _PERMIT2 && value != type(uint256).max`. | ||
if iszero(or(xor(shr(96, shl(96, spender)), _PERMIT2), iszero(not(value)))) { | ||
mstore(0x00, 0x3f68539a) // `Permit2AllowanceIsFixedAtInfinity()`. | ||
revert(0x1c, 0x04) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This expression's equivalence has been verified with Halmos.
@@ -503,7 +585,7 @@ abstract contract ERC20 { | |||
let allowanceSlot := keccak256(0x0c, 0x34) | |||
let allowance_ := sload(allowanceSlot) | |||
// If the allowance is not the maximum uint256 value. | |||
if add(allowance_, 1) { | |||
if not(allowance_) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This expression's equivalence has been verified with Halmos.
// If `spender == _PERMIT2 && amount != type(uint256).max`. | ||
if iszero(or(xor(shr(96, shl(96, spender)), _PERMIT2), iszero(not(amount)))) { | ||
mstore(0x00, 0x3f68539a) // `Permit2AllowanceIsFixedAtInfinity()`. | ||
revert(0x1c, 0x04) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This expression's equivalence has been verified with Halmos.
Description
✨
Confidence level is 99.999%.
transferFrom
logic is duplicated in a super left-curved way.Checklist
Ensure you completed all of the steps below before submitting your pull request:
forge fmt
?forge test
?Pull requests with an incomplete checklist will be thrown out.